#include "matchingdata.h"

static Graph* MD_readSerialize(char *filename);
static Graph* MD_getGraphRefine(char* matching,int w_id,char *base);
static int MD_getStats(Graph* ,StatType*,int *ids);
static int MD_getRefineStats(Graph* g,RefineStats *s);
static StatType* MD_readStat(char *filename,Graph **store_g,int* ids,StatIniType *si,char* F_graph,char* F_grid);

RefineStats** MD_readRefineStats(char** matching,int* m_ids,int* w_ids,char *base, int nb,Graph ***g){
  RefineStats** s;
  int i;

  if(nb == 0)
    return NULL;

  s = U_malloc(nb,RefineStats *,"MD_readRefineStats error code 1\n");

  /* if need to store graphs */
  if(g != NULL){
    *g = U_malloc(nb,Graph*,"MD_readStats error code 1\n");
  }

  printf("computing refinement stats ");fflush(stdout);
  for(i=0;i<nb;i++){
    if(m_ids[i] == -1)
      continue;

    if(g == NULL)
      s[i] = MD_readRefineStat(matching[m_ids[i]],w_ids[i],base,NULL);
    else
      s[i] = MD_readRefineStat(matching[m_ids[i]],w_ids[i],base,&((*g)[i]));
    printf(".");fflush(stdout);
  }
  printf("\n");
  
  return s;
}

Graph* MD_getGraphRefine(char* matching,int w_id,char *base){
  Graph* g;
  char filename[256];
  PlotGraphType* g_bet=NULL;
  FILE* fp;
  int *bet_where=NULL;
  int j,nvtxs;
  PlotGraphType* graph;

  /* read level matchings */
  g = MD_readSerialize(matching);
  /* read level refinement */
  g->levels = PLIBG_ReadWhere(g->graph,base,w_id);

  graph = g->graph;
  nvtxs = graph->nvtxs;
  
  /* first where is after et get result before et */
  /* insert new graph after the first one (copy) */
  g_bet = PLIBG_Init();
  PLIBG_Copy(g_bet,graph);
  PLIBG_Insert(graph,g_bet);
  g->levels++; 
  
  /* try to read where otherwise keep a copy */
  sprintf(filename,"%s.result.bet.%d",base,w_id);
  if((fp = fopen(filename,"r")) != NULL){
    bet_where = g_bet->pro;
    for(j=0;j<nvtxs;j++){
      fscanf(fp,"%d",bet_where+j);
    }
    /* replace where */
    fclose(fp);
    /* else undo automatic where update */
  }else{
    memcpy(g_bet->pro,graph->pro,nvtxs*sizeof(int));    
  }
  return g;
}
Graph** MD_getGraphsRefine(char** matchings,int* m_ids,int* w_ids,int *ids,
			   char *base,int nb){
  Graph** gs = U_malloc(nb,Graph *,"MD_getGraphsRefine error code 1\n");
  int i;
    
  WARNING((nb>MAX_GRAPHS,"MD_getGraphsRefine error code 1 : you are trying to put %d matchings into memory .... \n",nb),NULL);

  for(i=0;i<nb;i++){
    gs[i] = MD_getGraphRefine(matchings[m_ids[ids[i]]],w_ids[ids[i]],base);
  }

  return gs;
}
Graph** MD_getGraphs(char** matchings,int* ids,int nb){
  Graph** gs = U_malloc(nb,Graph*,"MD_getGraphs error code 1\n");
  int i;

  WARNING((nb>MAX_GRAPHS,"MD_getGraphsRefine error code 1 : you are trying to put %d matchings into memory .... \n",nb),NULL);

  for(i=0;i<nb;i++){
    gs[i] = MD_readSerialize(matchings[ids[i]]);
  }
  return gs;
}

RefineStats* MD_readRefineStat(char* matching,int where,char *base,Graph **store_g){
  Graph *g;
  RefineStats* RStat;
  FILE* fp;

  RStat = U_malloc(1,RefineStats,"MD_readRefineStat error code 1\n");

  /* read matching */
  g = MD_getGraphRefine(matching,where,base);
  WARNING(((fp = fopen(g->F_grid,"r")) == NULL,
	   "MD_readRefineStat error code 2 : cannot open %s\n",g->F_grid),
	  NULL);
  g->grid = PLIBN_Read(fp);
  fclose(fp);
  PLIBN_Progen(g->graph, g->grid);
  
  /* get stats */
  MD_getRefineStats(g,RStat);

  if(store_g == NULL)
    MD_freeGraph(g);
  else{
    PLIBN_Free(g->grid);
    g->grid = NULL;
    *store_g = g;
  }
  return RStat;
}

StatType** MD_readStats(char **files,int nb,Graph ***g,int **ids,char* F_graph,char* F_grid){
  StatType **s;
  StatIniType *si;
  int i;

  if(nb == 0)
    return NULL;

  /* if need to store graphs */
  if(g != NULL){
    *g = U_malloc(nb,Graph*,"MD_readStats error code 1\n");
  }

  printf("reading matching files and computing stats ");
  s = U_malloc(nb,StatType *,"MD_readStats error code 2\n");
  
  si = MD_StatIniAlloc(ids,nb);

  for(i=0;i<nb;i++){
    if(ids != NULL){
      if(g == NULL){
	s[i] = MD_readStat(files[i],NULL,ids[i],si,F_graph,F_grid);
      }else{
	s[i] = MD_readStat(files[i],&((*g)[i]),ids[i],si,F_graph,F_grid);
      }
    }else{
      if(g == NULL){
	s[i] = MD_readStat(files[i],NULL,NULL,si,F_graph,F_grid);
      }else{
	s[i] = MD_readStat(files[i],&((*g)[i]),NULL,si,F_graph,F_grid);
      }
    }
    printf(".");
    fflush(stdout);
  }
  printf("\n");

  return s;
}

StatType* MD_readStat(char *filename,Graph **store_g,int* ids,StatIniType *si,char* F_graph,char* F_grid){
  StatType* s;
  Graph *g;
  
  s = U_malloc(1,StatType,"MD_readStat error code 1\n");
  s->levels = 0;
  s->data = s->degree = s->cutedge = s->weight = NULL;
  s->nb_edges = s->nb_vertices = NULL;
  s->filename = filename;
  s->scheme = NULL;
  s->ini = si;
  g = MD_readSerialize(filename);
  strcpy(g->F_graph,F_graph);
  strcpy(g->F_grid,F_grid);

  WARNING((MD_getStats(g,s,ids) == 0,"MD_readStat error code 2 : error in MD_getStats\n"),s);
    
  if(store_g == NULL)
    MD_freeGraph(g);
  else{
    *store_g = g;
  }

  return s;
}

int MD_getRefineStats(Graph* g,RefineStats *s){
  double *ptr1;
  StatValues *ptr2;
  int levels;
  int i,npro = 0;
  PlotGraphType *lvlg = g->graph;

  npro = g->grid->npro;
  levels = s->levels = g->levels;

  ptr1 = s->data = (double *)U_smalloc(1,(levels + 1)*sizeof(double*) + ((8*(levels + 1)) + (npro*(levels + 1)))*sizeof(double) + 2*(levels + 1)*sizeof(StatValues),"MD_readStat error code 3\n");
  s->cutedge 	= ptr1;
  s->tcc	= ptr1 +   levels + 1;
  s->imbalance	= ptr1 + 2*levels + 2;
  s->met[0]	= ptr1 + 3*levels + 3;
  s->met[1]	= ptr1 + 4*levels + 4;
  s->met[2]	= ptr1 + 5*levels + 5;
  s->met[3]	= ptr1 + 6*levels + 6;
  s->met[4]	= ptr1 + 7*levels + 7;
  s->exec       = (double**)(ptr1 + 8*levels + 8);
  ptr1 = (double*)(((double**)(ptr1 + 8*levels + 8)) + (levels + 1));
  for(i=0;i<=levels;i++){
    s->exec[i] = ptr1 + (npro*i);
  }

  ptr2 = (StatValues *)(ptr1 + (npro*(levels + 1)));

  /*  ptr2 = (StatValues *)(ptr1 + 8*levels + 8);*/
  s->proVW	= ptr2;
  s->proET	= ptr2 +   levels + 1;
  s->nparts     = g->grid->npro;

  for(i=0;i<=levels;i++){
    PLIBN_RefineStats(lvlg,g->grid,
		      &(s->cutedge[i]),&(s->tcc[i]),&(s->imbalance[i]),
		      &(s->met[0][i]),&(s->met[1][i]),&(s->met[2][i]),
		      &(s->met[3][i]),&(s->met[4][i]),
		      &(s->proVW[i].min),&(s->proVW[i].max),
		      &(s->proVW[i].avg),&(s->proVW[i].stddev),
		      &(s->proVW[i].sum),s->exec[i],
		      &(s->proET[i].min),
		      &(s->proET[i].max),&(s->proET[i].avg),
		      &(s->proET[i].stddev),&(s->proET[i].sum));
    lvlg = lvlg->child;
  }
  return 1;
}

int MD_getStats(Graph* graph,StatType* stat,int* ids){
  StatValues *Sdata,*degree,*cutedge,*weight,*eweight;
  FILE* fp;
  int *Idata;
  int levels = 0,i;
  PlotGraphType* lvl_graph = graph->graph;
  int *nb_vertices,*nb_edges;
  int j;
  int nb_ids = ids[0];
  int id;
  int nvtxs = 0;
  int* where;
  int* old_where;
  char F_output[256];
  char filename1[256],filename2[256];
  void *grid = NULL;


  levels = stat->levels = graph->levels;

  Idata = (int *)U_smalloc(1,2*(levels+1)*sizeof(int) + 4*(levels+1)*sizeof(StatValues),"MD_getStats error code 1\n");
  stat->data = (StatValues *)Idata;
  
  nb_edges    = stat->nb_edges    = Idata;
  nb_vertices = stat->nb_vertices = Idata + levels + 1;
  Sdata = (StatValues *)(Idata + 2*levels + 2);
  degree      = stat->degree      = Sdata;
  cutedge     = stat->cutedge     = Sdata + levels + 1;
  weight      = stat->weight      = Sdata + 2*levels + 2;
  eweight     = stat->eweight     = Sdata + 3*levels + 3;

  CALL2VAL(graph->tool,GetScheme(graph->CType,graph->WType,graph->RType,
				 graph->CSeed,graph->ISeed,graph->RSeed),
	   stat->scheme)
  for(i=0;i<=levels;i++){
    nb_edges[i]    = lvl_graph->nedges/2;
    nb_vertices[i] = lvl_graph->nvtxs;    
    PLIBG_DegreeStats(lvl_graph,&(degree[i].min),&(degree[i].max),
		     &(degree[i].avg),&(degree[i].stddev),&(degree[i].sum));
    
    PLIBG_CutEdgeStats(lvl_graph,&(cutedge[i].min),&(cutedge[i].max),
		       &(cutedge[i].avg),&(cutedge[i].stddev),&(cutedge[i].sum));
    PLIBG_WeightStats(lvl_graph,&(weight[i].min),&(weight[i].max),
		      &(weight[i].avg),&(weight[i].stddev),&(weight[i].sum));
    PLIBG_EweightStats(lvl_graph,&(eweight[i].min),&(eweight[i].max),
		       &(eweight[i].avg),&(eweight[i].stddev),&(eweight[i].sum));

    /* initial partitioning */
    if(i == levels && ids != 0){
      nvtxs = lvl_graph->nvtxs;
      where = U_malloc(nvtxs,int,"MD_getStats error code 2\n");
      U_filename(filename1,graph->F_graph);
      U_filename(filename2,graph->F_grid);
      sprintf(F_output,"%s.%s",filename1,filename2);
      WARNING(((fp=fopen(graph->F_grid,"r"))==NULL,"MD_getStats error code 3 : cannot open %s\n",graph->F_grid),0);
      grid = PLIBN_Read(fp);
      fclose(fp);
      PLIBN_Progen(graph->graph, grid);

      for(j=1;j<=nb_ids;j++){
	id = ids[j];
	/* get where info */
	where = PLIBG_ReadIniWhere(lvl_graph,F_output,id,where);
	/* temp switch */
	PLIBG_SwitchWhere(lvl_graph,where,&old_where);
	/* compute stats */
	PLIBG_DegreeStats(lvl_graph,
			  &(stat->ini->degree[id].min),
			  &(stat->ini->degree[id].max),
			  &(stat->ini->degree[id].avg),
			  &(stat->ini->degree[id].stddev),
			  &(stat->ini->degree[id].sum));
	PLIBN_CutEdgeStats(lvl_graph,
			   &(stat->ini->cutedge[id].min),
			   &(stat->ini->cutedge[id].max),
			   &(stat->ini->cutedge[id].avg),
			   &(stat->ini->cutedge[id].stddev),
			   &(stat->ini->cutedge[id].sum),grid);
	PLIBG_WeightStats(lvl_graph,
			  &(stat->ini->weight[id].min),
			  &(stat->ini->weight[id].max),
			  &(stat->ini->weight[id].avg),
			  &(stat->ini->weight[id].stddev),
			  &(stat->ini->weight[id].sum));
	PLIBG_EweightStats(lvl_graph,
			   &(stat->ini->eweight[id].min),
			   &(stat->ini->eweight[id].max),
			   &(stat->ini->eweight[id].avg),
			   &(stat->ini->eweight[id].stddev),
			   &(stat->ini->eweight[id].sum));
	PLIBN_Imbalance(lvl_graph,&(stat->ini->imbalance[id]),grid);
	/* undo switch */
	PLIBG_SwitchWhere(lvl_graph,old_where,&where);
      }
      PLIBN_Free(grid);
      U_free("MD_getStats error code 2\n",&where,LEND);
    }
    lvl_graph = lvl_graph->child;
  }
  return 1;
}

Graph* MD_readSerialize(char *filename){
  Graph *graph;
  
  graph = U_malloc(1,Graph,"MD_readSerialize error code 1\n");
  graph->graph = NULL;
  graph->grid  = NULL;  

  graph->graph = PLIBG_Unserialize(&(graph->tool),filename,NULL,
				   &(graph->F_graph),&(graph->F_grid),
				   &(graph->levels),
				   &(graph->CType),&(graph->WType),&(graph->RType),
				   &(graph->CSeed),&(graph->ISeed),&(graph->RSeed));  

  while(graph->graph->father != NULL)
    graph->graph = graph->graph->father;

  return graph;
}

double* MD_getRefineData(RefineStats* s,int x,int x_stat,int x_value,int x_type){
  double *values;
  int i;
  values = U_malloc(s->levels+2,double,"MD_getRefineData error code 1\n");
  values[0] = s->levels+1;
  if(x_stat == 1){
    switch(x_value){
    case R_PROVW:
      switch(x_type){
      case MIN:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proVW[i].min;
	}
	return values;
      case MAXI:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proVW[i].max;
	}
	return values;
      case AVG:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proVW[i].avg;
	}
	return values;
      case STDDEV:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proVW[i].stddev;
	}
	return values;
      case SUM:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proVW[i].sum;
	}
	return values;
      default:
	WARNING((1,"MD_getRefineData error code 2 : unknown type\n"),NULL);
      }
      break;
    case R_PROET:
      switch(x_type){
      case MIN:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].min;
	}
	return values;
      case MAXI:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].max;
	}
	return values;
      case AVG:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].avg;
	}
	return values;
      case STDDEV:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].stddev;
	}
	return values;
      case SUM:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].sum;
	}
	return values;
      case IM:
	for(i=0;i<=s->levels;i++){
	  values[i+1] = s->proET[i].max / s->proET[i].avg;
	}
	return values;
      default:
	WARNING((1,"MD_getRefineData error code 3 : unknown type\n"),NULL);
      }
      break;
    default:
      WARNING((1,"MD_getRefineData error code 4 : unknown value (%d)\n",x_value),NULL);
    }
  }
  
  switch(x){
  case R_CUTEDGE:
    memcpy(values+1,s->cutedge,(s->levels+1)*sizeof(double));
    return values;
  case R_TCC:
    memcpy(values+1,s->tcc,(s->levels+1)*sizeof(double));
    return values;
  case R_IMBALANCE:
    memcpy(values+1,s->imbalance,(s->levels+1)*sizeof(double));
    return values;
  case R_MET:
    memcpy(values+1,s->met[0],(s->levels+1)*sizeof(double));
    return values;
  case R_MET025:
    memcpy(values+1,s->met[1],(s->levels+1)*sizeof(double));
    return values;
  case R_MET05:
    memcpy(values+1,s->met[2],(s->levels+1)*sizeof(double));
    return values;
  case R_MET1:
    memcpy(values+1,s->met[3],(s->levels+1)*sizeof(double));
    return values;
  case R_MET2:
    memcpy(values+1,s->met[4],(s->levels+1)*sizeof(double));
    return values;
  default:
    WARNING((1,"MD_getRefineData error code 5 : unknown value\n"),NULL);
  }
  return NULL;
}

double* MD_getLevelData(StatType *s,int type,int value,int id){
  double *arr = NULL;
  int i;
  
  arr = U_malloc(s->levels+3,double,"MD_getLevelData error code 2\n");
  arr[0] = s->levels + 2;
  switch(type){
  case NB_VERTICES:
    for(i=0;i<=s->levels;i++){
      arr[i+1] = s->nb_vertices[i];
    }
    arr[i+1] = s->nb_vertices[i-1];
    return arr;
  case NB_EDGES:
    for(i=0;i<=s->levels;i++){
      arr[i+1] = s->nb_edges[i];
    }
    arr[i+1] = s->nb_edges[i-1];
    return arr;
  case DEGREE:
    switch(value){
    case MIN:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->degree[i].min;
      arr[i+1] = s->ini->degree[id].min;
      return arr;
    case MAXI:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->degree[i].max;
      arr[i+1] = s->ini->degree[id].max;
      return arr;
    case AVG:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->degree[i].avg;
      arr[i+1] = s->ini->degree[id].avg;
      return arr;
    case STDDEV:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->degree[i].stddev;
      arr[i+1] = s->ini->degree[id].stddev;
      return arr;
    case SUM:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->degree[i].sum;
      arr[i+1] = s->ini->degree[id].sum;
      return arr;
    default:
      WARNING((1,"MD_getLevelData error code 1 : unknown stat value\n"),NULL);
    }
    break;
  case WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->weight[i].min;
      arr[i+1] = s->ini->weight[id].min;
      return arr;
    case MAXI:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->weight[i].max;
      arr[i+1] = s->ini->weight[id].max;
      return arr;
    case AVG:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->weight[i].avg;
      arr[i+1] = s->ini->weight[id].avg;
      return arr;
    case STDDEV:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->weight[i].stddev;
      arr[i+1] = s->ini->weight[id].stddev;
      return arr;
    case SUM:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->weight[i].sum;
      arr[i+1] = s->ini->weight[id].sum;
      return arr;
    default:
      WARNING((1,"MD_getLevelData error code 2 : unknown stat value\n"),NULL);
    }
    break;
  case CUTEDGE:
    switch(value){
    case MIN:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->cutedge[i].min;
      arr[i+1] = s->ini->cutedge[id].min;
      return arr;
    case MAXI:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->cutedge[i].max;
      arr[i+1] = s->ini->cutedge[id].max;
      return arr;
    case AVG:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->cutedge[i].avg;
      arr[i+1] = s->ini->cutedge[id].avg;
      return arr;
    case STDDEV:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->cutedge[i].stddev;
      arr[i+1] = s->ini->cutedge[id].stddev;
      return arr;
    case SUM:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->cutedge[i].sum;
      arr[i+1] = s->ini->cutedge[id].sum;
      return arr;
    default:
      WARNING((1,"MD_getLevelData error code 3 : unknown stat value\n"),NULL);
    }
    break;
  case E_WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->eweight[i].min;
      arr[i+1] = s->ini->eweight[id].min;
      return arr;
    case MAXI:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->eweight[i].max;
      arr[i+1] = s->ini->eweight[id].max;
      return arr;
    case AVG:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->eweight[i].avg;
      arr[i+1] = s->ini->eweight[id].avg;
      return arr;
    case STDDEV:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->eweight[i].stddev;
      arr[i+1] = s->ini->eweight[id].stddev;
      return arr;
    case SUM:
      for(i=0;i<=s->levels;i++)
	arr[i+1] = s->eweight[i].sum;
      arr[i+1] = s->ini->eweight[id].sum;
      return arr;
    default:
      WARNING((1,"MD_getLevelData error code 3 : unknown stat value\n"),NULL);
    }
    break;
  default:
    WARNING((1,"MD_getLevelData error code 4 : unknown type\n"),NULL);
  }
  return NULL;
}
double* MD_getDataArray(StatType **s,int size,int type,int value){
  int i;
  double *arr = NULL;

  arr = U_malloc(size,double,"MD_getDataArray error code 2\n");

  switch(type){
  case NB_VERTICES:
    for(i=0;i<size;i++){
      arr[i] = s[i]->nb_vertices[s[i]->levels];
    }
    return arr;
  case NB_EDGES:
    for(i=0;i<size;i++){
      arr[i] = s[i]->nb_edges[s[i]->levels];
    }
    return arr;
  case DEGREE:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[i]->degree[s[i]->levels].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[i]->degree[s[i]->levels].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[i]->degree[s[i]->levels].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[i]->degree[s[i]->levels].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[i]->degree[s[i]->levels].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getDataArray error code 4 : unknown value\n"),NULL);
    }
    break;
  case WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[i]->weight[s[i]->levels].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[i]->weight[s[i]->levels].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[i]->weight[s[i]->levels].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[i]->weight[s[i]->levels].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[i]->weight[s[i]->levels].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getDataArray error code 5 : unknown value\n"),NULL);
    }
    break;
  case CUTEDGE:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[i]->cutedge[s[i]->levels].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[i]->cutedge[s[i]->levels].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[i]->cutedge[s[i]->levels].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[i]->cutedge[s[i]->levels].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	/*printf("level %d %f\n",s[i]->levels,s[i]->cutedge[s[i]->levels].sum);*/
	arr[i] = s[i]->cutedge[s[i]->levels].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getDataArray error code 6 : unknown value\n"),NULL);
    }
    break;
  case E_WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[i]->eweight[s[i]->levels].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[i]->eweight[s[i]->levels].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[i]->eweight[s[i]->levels].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[i]->eweight[s[i]->levels].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[i]->eweight[s[i]->levels].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getDataArray error code 6 : unknown value\n"),NULL);
    }
    break;
  default:
      WARNING((1,"MD_getDataArray error code 7 : unknown type\n"),NULL);
  }
  return NULL;
}
double* MD_getIniDataArray(StatType **s,int size,int type,int value,int* ids){
  int i;
  double *arr = NULL;

  arr = U_malloc(size,double,"MD_getIniDataArray error code 2\n");

  switch(type){
  case DEGREE:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->degree[ids[i]].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->degree[ids[i]].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->degree[ids[i]].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->degree[ids[i]].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->degree[ids[i]].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getIniDataArray error code 4 : unknown value\n"),NULL);
    }
    break;
  case WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->weight[ids[i]].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->weight[ids[i]].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->weight[ids[i]].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->weight[ids[i]].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->weight[ids[i]].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getIniDataArray error code 5 : unknown value\n"),NULL);
    }
    break;
  case CUTEDGE:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->cutedge[ids[i]].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->cutedge[ids[i]].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->cutedge[ids[i]].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->cutedge[ids[i]].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->cutedge[ids[i]].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getIniDataArray error code 6 : unknown value\n"),NULL);
    }
    break;
  case E_WEIGHT:
    switch(value){
    case MIN:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->eweight[ids[i]].min;
      }
      return arr;
    case MAXI:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->eweight[ids[i]].max;
      }
      return arr;
    case AVG:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->eweight[ids[i]].avg;
      }
      return arr;
    case STDDEV:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->eweight[ids[i]].stddev;
      }
      return arr;
    case SUM:
      for(i=0;i<size;i++){
	arr[i] = s[0]->ini->eweight[ids[i]].sum;
      }
      return arr;
    default:
      WARNING((1,"MD_getIniDataArray error code 6 : unknown value\n"),NULL);
    }
    break;
  case IMBALANCE:
    for(i=0;i<size;i++){
      arr[i] = s[0]->ini->imbalance[ids[i]];
    }
    return arr;
  default:
      WARNING((1,"MD_getIniDataArray error code 7 : unknown type\n"),NULL);
  }
  return NULL;
}

void MD_freeGraph(Graph *g){
  PLIBG_FreeMultiple(g->graph);
  PLIBN_Free(g->grid);
  U_free("MD_freeGraph error code 2\n",&(g->F_graph),&(g->F_grid),&g,LEND);
}
int MD_printMatchingStats(StatType *s,FILE* fp,int id){
  int *nb_edges = s->nb_edges;
  int *nb_vertices = s->nb_vertices;
  StatValues *degree = s->degree;
  StatValues *cutedge = s->cutedge;
  StatValues *weight = s->weight;
  StatValues *eweight = s->eweight;
  int i;
  /* header */
  if(ftell(fp) == 0 || fp == stdout){
    fprintf(fp,"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
    fprintf(fp,"| %5s | %7s | %8s || %12s%6s%12s || %16s%7s%17s || %14s%6s%13s || %9s%12s%9s ||\n",
	    "level","edges","vertices",
	    "","degree","",
	    "","cutedge","",
	    "","weight","",
	    "","edge weight","");
    fprintf(fp,"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
    fprintf(fp,"| %5s | %7s | %8s || %3s | %4s | %7s | %7s || %7s | %3s | %4s | %7s | %7s || %4s | %4s | %9s | %7s || %3s | %4s | %7s | %7s ||\n",
	    "","","",
	    "min","max","average","std dev","total",
	    "min","max","average","std dev",
	    "min","max","average","std dev",
	    "min","max","average","std dev");
    fprintf(fp,"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
  }
  fprintf(fp,"| %43s%38s %49s%44s ||\n","",s->scheme,s->filename,"");
  fprintf(fp,"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
  for(i=0;i<=s->levels;i++){
    fprintf(fp,"| %5d | %7d | %8d || %3d | %4d | %7.2f | %7.2f || %7d | %3d | %4d | %7.2f | %7.2f || %4d | %4d | %9.2f | %7.2f || %3d | %4d | %7.2f | %7.2f ||\n",i,nb_edges[i],nb_vertices[i],
	    (int)degree[i].min,(int)degree[i].max,degree[i].avg,degree[i].stddev,
	    (int)cutedge[i].sum,(int)cutedge[i].min,(int)cutedge[i].max,cutedge[i].avg,cutedge[i].stddev,
	    (int)weight[i].min,(int)weight[i].max,weight[i].avg,weight[i].stddev,
	    (int)eweight[i].min,(int)eweight[i].max,eweight[i].avg,eweight[i].stddev);
  }
  fprintf(fp,"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
  fprintf(fp,"| %5s | %7d | %8d || %3d | %4d | %7.2f | %7.2f || %7d | %3d | %4d | %7.2f | %7.2f || %4d | %4d | %9.2f | %7.2f || %3d | %4d | %7.2f | %7.2f ||\n","final",nb_edges[i-1],nb_vertices[i-1],
	  (int)s->ini->degree[id].min,(int)s->ini->degree[id].max,s->ini->degree[id].avg,s->ini->degree[id].stddev,
	  (int)s->ini->cutedge[id].sum,(int)s->ini->cutedge[id].min,(int)s->ini->cutedge[id].max,s->ini->cutedge[id].avg,s->ini->cutedge[id].stddev,
	  (int)s->ini->weight[id].min,(int)s->ini->weight[id].max,s->ini->weight[id].avg,s->ini->weight[id].stddev,
	  (int)s->ini->eweight[id].min,(int)s->ini->eweight[id].max,s->ini->eweight[id].avg,s->ini->eweight[id].stddev);
  fprintf(fp,"| %20s : %20.5f %131s ||\n","imbalance",s->ini->imbalance[id],"");
  fprintf(fp,"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
  return 1;
}

double** MD_getGraphData(Graph *g,int type,char *matching,char ***plot_names,int *nb_values){
  double **values;
  char buf[9];
  PlotGraphType* lvl_graph = g->graph;
  int i,levels;
  levels = g->levels ;
  *nb_values = levels + 1;
  
  values = U_malloc(levels + 1,double *,"MD_getGraphData error code 1\n");
  /**plot_names = U_malloc(levels + 1,char *,"MD_getGraphData error code 2\n");*/
  *plot_names = U_mallocxy(levels+1,strlen(matching)+50,char,"MD_getGraphData error code 2\n");
  for(i=0;i<=levels;i++){
    /*(*plot_names)[i] = U_malloc(strlen(matching) + 50,char,"MD_getGraphData error code 2\n");*/
    strcpy((*plot_names)[i],matching);
    sprintf(buf,".%s.%d","level",i);
    strcat((*plot_names)[i],buf);
  }

  for(i=0;i<=levels;i++){
    switch(type){
    case DEGREE:
      values[i] = PLIBG_VtxsDegree(lvl_graph,NULL);
      break;
    case WEIGHT:
      values[i] = PLIBG_VtxsWeight(lvl_graph,NULL);
      break;
    case CUTEDGE:
      values[i] = PLIBG_VtxsCutedge(lvl_graph,NULL);
      break;
    }
    lvl_graph = lvl_graph->child;
  }
  
  return values;
}

void MD_free(StatType* s){
  if(s!=NULL)
    U_free("MD_free error code 2\n",&(s->scheme),&(s->data),&(s),LEND);
}

void MD_freeArr(StatType** s,int size){
  int i;
  if(s != NULL){
    MD_freeI(s[0]->ini);
    for(i=0;i<size;i++)
      MD_free(s[i]);
    U_free("MD_freeArr error code 1\n",&s,LEND);
  }else{
    NOTICE((1,"MD_freeArr error code 2 : NULL array passed\n"));
  }
}
void MD_freeI(StatIniType *s){
  if(s!=NULL){
    U_free("MD_freeI error code 1\n",&(s->data),LEND);
    U_free("MD_freeI error code 2\n",&(s),LEND);
  }
}
void MD_freeR(RefineStats *s){
  if(s != NULL){
    U_free("MD_freeR error code 1\n",&(s->data),&(s),LEND);
  }
}
void MD_freeArrR(RefineStats **s,int nb){
  int i;
  if(s != NULL){
    for(i=0;i<nb;i++)
      MD_freeR(s[i]);
    U_free("MD_freeArrR error code 1\n",&(s),LEND);
  }
}
StatIniType* MD_StatIniAlloc(int **ids,int nb){
  StatIniType* si = U_malloc(1,StatIniType,"MD_StatIniAlloc error code 1\n");
  StatValues *data;
  int nb_ids = 0;
  int i;
  if(ids != NULL)
    for(i=0;i<nb;i++)
      nb_ids += ids[i][0];
  else
    nb_ids = 1;
  nb_ids++; /* ids start at 1 */

  si->ids = nb_ids;
  data = si->data = (StatValues *)U_smalloc(1,nb_ids*4*sizeof(StatValues) + nb_ids*sizeof(double),"MD_StatIniAlloc error code 2\n");
  si->degree      = data;
  si->cutedge     = data + nb_ids;
  si->weight      = data + 2*nb_ids;
  si->eweight     = data + 3*nb_ids;
  si->imbalance   = (double*)(data + 4*nb_ids);

  return si;
}
int MD_BestByMethod(StatIniType* s,int value,int type,int minmax,double *val,int *id){
  int i;
  int size = s->ids;
  double b = -1;
  int b_id = 1;

  if(s==NULL){
    *val = 0;
    *id  = 0;
    return 1;
  }
  
  switch(value){
  case DEGREE:
    switch(type){
    case MIN:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->degree[i].min < b || b == -1.0){b = s->degree[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->degree[i].min > b){b = s->degree[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case MAXI:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->degree[i].max < b || b == -1.0){b = s->degree[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->degree[i].max > b){b = s->degree[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case AVG:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->degree[i].avg < b || b == -1.0){b = s->degree[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->degree[i].avg > b){b = s->degree[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case STDDEV:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->degree[i].stddev < b || b == -1.0){b = s->degree[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->degree[i].stddev > b){b = s->degree[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case SUM:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->degree[i].sum < b || b == -1.0){b = s->degree[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->degree[i].sum > b){b = s->degree[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    default:
      WARNING((1,"MD_BestByMethod error code : unknown type\n"),0);
    }
    break;
  case WEIGHT:
    switch(type){
    case MIN:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->weight[i].min < b || b == -1.0){b = s->weight[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->weight[i].min > b){b = s->weight[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case MAXI:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->weight[i].max < b || b == -1.0){b = s->weight[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->weight[i].max > b){b = s->weight[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case AVG:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->weight[i].avg < b || b == -1.0){b = s->weight[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->weight[i].avg > b){b = s->weight[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case STDDEV:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->weight[i].stddev < b || b == -1.0){b = s->weight[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->weight[i].stddev > b){b = s->weight[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case SUM:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->weight[i].sum < b || b == -1.0){b = s->weight[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->weight[i].sum > b){b = s->weight[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    default:
      WARNING((1,"MD_BestByMethod error code : unknown type\n"),0);
    }
    break;
  case CUTEDGE:
    switch(type){
    case MIN:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->cutedge[i].min < b || b == -1.0){b = s->cutedge[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->cutedge[i].min > b){b = s->cutedge[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case MAXI:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->cutedge[i].max < b || b == -1.0){b = s->cutedge[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->cutedge[i].max > b){b = s->cutedge[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case AVG:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->cutedge[i].avg < b || b == -1.0){b = s->cutedge[i].avg;b_id = i;}
	*val = b;*id = b_id;
	return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->cutedge[i].avg > b){b = s->cutedge[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case STDDEV:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->cutedge[i].stddev < b || b == -1.0){b = s->cutedge[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->cutedge[i].stddev > b){b = s->cutedge[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case SUM:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->cutedge[i].sum < b || b == -1.0){b = s->cutedge[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->cutedge[i].sum > b){b = s->cutedge[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    default:
      WARNING((1,"MD_BestByMethod error code : unknown type\n"),0);
    }
    break;
  case IMBALANCE:
    switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->imbalance[i] < b || b == -1.0){b = s->imbalance[i];b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->imbalance[i] > b){b = s->imbalance[i];b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
    break;
  case E_WEIGHT:
    switch(type){
    case MIN:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->eweight[i].min < b || b == -1.0){b = s->eweight[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->eweight[i].min > b){b = s->eweight[i].min;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case MAXI:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->eweight[i].max < b || b == -1.0){b = s->eweight[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->eweight[i].max > b){b = s->eweight[i].max;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case AVG:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->eweight[i].avg < b || b == -1.0){b = s->eweight[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->eweight[i].avg > b){b = s->eweight[i].avg;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case STDDEV:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->eweight[i].stddev < b || b == -1.0){b = s->eweight[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->eweight[i].stddev > b){b = s->eweight[i].stddev;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    case SUM:
      switch(minmax){
      case MIN:
	for(i=1;i<size;i++)if(s->eweight[i].sum < b || b == -1.0){b = s->eweight[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      case MAXI:
	for(i=1;i<size;i++)if(s->eweight[i].sum > b){b = s->eweight[i].sum;b_id = i;}
	*val = b;*id = b_id;return 1;
      default:
	WARNING((1,"MD_BestByMethod error code : unknown minmax\n"),0);
      }
      break;
    default:
      WARNING((1,"MD_BestByMethod error code : unknown type\n"),0);
    }
  default:
    WARNING((1,"MD_BestByMethod error code : unknown value\n"),0);
  }
  return 0;
}
